package org.ziegler.zunit;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.function.Predicate;

import org.junit.platform.commons.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class ZUnitHumanObjBase implements ZUnitHumanObj {
    /** 日志模块 */
    private final Logger logger = LoggerFactory.getLogger("ZUnitTest");

    private final String methodName;

    /** 测试函数调用成功数量 */
    private int invokeSuccessNum = 0;
    /** 测试函数调用失败数量 */
    private int invokeFailureNum = 0;

    public ZUnitHumanObjBase(String methodName) {
        this.methodName = methodName;
    }

    @Override
    public void test(HumanObject humanObj) {
        if (StringUtils.isBlank(methodName)) {
            logger.info("测试模块[{}]调用所有测试函数", this.getClass().getSimpleName());
            resetInvokeNum();
            invokeTestMethod(humanObj, method -> true);
            printStatistics();
        } else {
            logger.info("测试模块[{}]调用函数：{}", this.getClass().getSimpleName(), methodName);
            resetInvokeNum();
            final int invokeTotalNum = invokeTestMethod(humanObj, method -> method.getName().equalsIgnoreCase(methodName));
            if (invokeTotalNum == 0) {
                logger.error("调用测试函数[{}]不存在。", methodName);
            }
        }
    }

    @Override
    public void test() {

    }

    private int invokeTestMethod(HumanObject humanObj, Predicate<Method> filter) {
        for (Method method : this.getClass().getDeclaredMethods()) {
            if (method.isAnnotationPresent(Test.class)) {
                if (filter.test(method)) {
                    if (!Modifier.isStatic(method.getModifiers())) {
                        if (isParamHumanObject(method)) {
                            invokeMethod(humanObj, method);
                        }
                    } else {
                        // 静态方法
                    }
                }
            }
        }

        return getInvokeTotalNum();
    }

    private boolean isParamHumanObject(Method method) {
        return (method.getParameterTypes().length == 1)
                && method.getParameterTypes()[0].equals(HumanObject.class);
    }

    private void invokeMethod(HumanObject humanObj, Method method) {
        method.setAccessible(true);
        // 函数调用
        try {
            logger.info(">>>>>>>>>> 调用测试函数之前：{}", method.getName());
            method.invoke(this, humanObj);
            ++invokeSuccessNum;
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            ++invokeFailureNum;
            logger.error(e.getMessage(), e.getCause());
        } catch (InvocationTargetException e) {
            ++invokeFailureNum;
            logger.error(e.getMessage(), e.getCause());
        } catch (Exception e) {
            ++invokeFailureNum;
            logger.error(e.getMessage(), e.getCause());
        } finally {
            logger.info("<<<<<<<<<< 调用测试函数之后：{}\n", method.getName());
        }
    }

    private void resetInvokeNum() {
        invokeSuccessNum = 0;
        invokeFailureNum = 0;
    }

    private int getInvokeTotalNum() {
        return invokeSuccessNum + invokeFailureNum;
    }

    private void printStatistics() {
        logger.info("调用总共的测试函数数量：{}", getInvokeTotalNum());
        logger.info("调用成功的测试函数数量：{}", invokeSuccessNum);
        logger.info("调用失败的测试函数数量：{}", invokeFailureNum);
    }

}

